#ifndef PM_DB_OBJECT_H_INCLUDED
#define PM_DB_OBJECT_H_INCLUDED

#include <wx/string.h>
#include <wx/datetime.h>
#include <wx/wxsqlite3.h>
#include <wx/colour.h>
#include <list>

namespace db
{

/**
 * 
 */
struct NoCheckValidator
{
	template <typename T>
	static bool Check(const T& /*value*/)
	{
		return true;
	}
};
	
/**
 * 
 */
template <typename T, typename C, typename V = NoCheckValidator>
class Value
{
public:
	typedef T value_t;
	typedef C convert_functor;
	typedef V validator_t;

private:
	value_t   m_value;
	
public:
	Value(const value_t& v = value_t())
	: m_value(v)
	{
	}
	
	Value(wxSQLite3ResultSet& res, const wxString& colName, const value_t& defaultValue = value_t())
	{
		load(res, colName, defaultValue);
	}
	
	virtual ~Value()
	{
	}
	
	const value_t& operator()() const 
	{
		return get();
	}
	
	bool operator()(const value_t& v) 
	{
		return set(v);
	}
	
	bool load(wxSQLite3ResultSet& res, const wxString& colName, const value_t& defaultValue = value_t())
	{
		return set( convert_functor::load(res, colName, defaultValue) );
	}

protected:
	const value_t& get() const 
	{
		return m_value;
	}
		
	bool set(const value_t& v)
	{
		if (validator_t::Check(v) == false) {
			return false;
		}
		m_value = v;
		return true;
	}
};

/**
 * 
 */
struct int_converter
{
	static
	int load(wxSQLite3ResultSet& res, const wxString& colName, int defaultValue)
	{
		return res.GetInt(colName, defaultValue);
	}
};

/**
 * 
 */
struct double_converter
{
	static
	double load(wxSQLite3ResultSet& res, const wxString& colName, double defaultValue)
	{
		return res.GetDouble(colName, defaultValue);
	}
};

/**
 * 
 */
struct string_converter
{
	static
	wxString load(wxSQLite3ResultSet& res, const wxString& colName, const wxString& defaultValue)
	{
		return res.GetString(colName, defaultValue);
	}
};

/**
 * 
 */
struct date_converter
{
	static
	wxDateTime load(wxSQLite3ResultSet& res, const wxString& colName, const wxDateTime& WXUNUSED(defaultValue))
	{
		return res.GetDate(colName);
	}
};

/**
 * 
 */
struct colour_converter
{
	static
	wxColour load(wxSQLite3ResultSet& res, const wxString& colName, const wxColour& /*defaultValue*/)
	{
		wxColour c;
		c.Set(res.GetString(colName));
		return c;
	}
};


typedef Value<int,        int_converter>    integer;
typedef Value<double,     double_converter> real;
typedef Value<wxString,   string_converter> text;
typedef Value<wxDateTime, date_converter>   date;
typedef Value<wxColour,   colour_converter> colour;

class ID : public integer
{
public:
	enum { undefined = -1 };

	ID(integer::value_t v = undefined)
	: integer(v)
	{
	}

	ID(wxSQLite3ResultSet& res, const wxString& colName, const value_t& defaultValue = undefined)
	{
		load(res, colName, defaultValue);
	}
	
	bool valid() const
	{
		return get() != undefined;
	}
};

typedef std::pair<bool, wxSQLite3Statement> update_value_t;

/**
 * 
 */
class Object
{
protected:
    Object() { }
	virtual ~Object() { }
	
public:
	virtual bool load(wxSQLite3ResultSet& res) = 0;
};

/**
 * 
 */
class Table : public Object
{
	ID m_id;

protected:
    Table();
	
    Table(wxSQLite3ResultSet& res);

public:
	int id() const { return m_id(); }

    bool valid() const { return m_id.valid(); }
	
	bool insert(wxSQLite3Database& db);
	
	bool update(wxSQLite3Database& db);

	virtual bool load(wxSQLite3ResultSet& res);
	
protected:
	int last_insert_id(wxSQLite3Database& db);

	virtual update_value_t prepare_insert(wxSQLite3Database& db) = 0;
	virtual update_value_t prepare_update(wxSQLite3Database& db) = 0;
};

} // namespace db

#endif // PM_DB_OBJECT_H_INCLUDED
